#define _CRT_SECURE_NO_WARNINGS 1

// 整数在内存中的存储
// 对于整型来说，数据存放内存其实放的就是补码1

// 大小端字节序存储
// 大端字节序存储，小端字节序存储
// 大端存储模式：数据的低位字节内容保存在内存的高地址处
// 小端存储模式：数据的低位字节内容保存在内存的低地址处

// 小端存储模式
// #include <stdio.h>

//int main()
//{
//	int a = 0x11223344;
//	char* pa = &a;
//	
//	for (int i = 0; i < 4; i++) {
//		printf("%x ", *pa);
//		pa++;
//	}
//	return 0;
//}

//int main()
//{
//	int a = 1;
//	char* pa = (char*)&a;
//
//	if (*pa == 1) printf("小端\n");
//	else printf("大端\n");
//
//	return 0;
//}

//int main()
//{
//	// 数据存储在a中需要发生截断
//	char a = -1;
//	signed char b = -1;
//	unsigned char c = -1;
//
//	printf("a = %d, b = %d, c = %d", a, b, c);
//
//	return 0;
//}

//int main()
//{
//	char a = -128;
//	// 10000000 00000000 00000000 10000000 原码
//	// 11111111 11111111 11111111 01111111 补码
//	// 11111111 11111111 11111111 10000000 反码
//	// 10000000 a
//	// 打印的时候发生整型提升
//	// 11111111 11111111 11111111 10000000
//	printf("%u\n", a);
//
//
//	return 0;
//}

//#include <stdio.h>
//
//int main()
//{
//	char a = 128;
//	// 存不下，认为存的是-128
//	// 00000000 00000000 00000000 10000000
//	// 10000000 -- a
//	printf("%u\n", a);
//
//	return 0;
//}

//#include <stdio.h>
//
//int main()
//{
//	char a[1000];
//	for (int i = 0; i < 1000; i++) {
//		a[i] = -1 - i;
//	}
//
//	// 255
//	printf("%d", strlen(a));
//
//	return 0;
//}

//#include <stdio.h>
//
//unsigned char i = 0;
//
//int main()
//{
//	// 死循环
//	for (int i = 0; i <= 255; i++) {
//		printf("Hello, world!\n");
//	}
//
//	return 0;
//}

// x86 小端字节序
//#include <stdio.h>
//
//int main()
//{
//	int a[4] = { 1,2,3,4 };
//	int* ptr1 = (int*)(&a + 1);
//	int* ptr2 = (int*)((int)a + 1);
//
//	printf("%x, %x", ptr1[-1], *ptr2);
//	return 0;
//}

//#include <stdio.h>
//
//int main()
//{
//	// 可以观察到整数的存储方式和浮点数的存储方式是不一样的
//	int n = 9;
//	float* pFloat = (float*)&n; // int*
//
//	printf("n的值为:%d\n", n); // 9
//  // 打印出来为0的原因在下方
//	printf("*pFloat的值为:%f\n", *pFloat); // 0.000000
//
//	*pFloat = 9.0;
//	printf("num的值为:%d\n", n); // 1091567616
//	printf("*pFloat的值为:%f\n", *pFloat); // 9.000000
//
//	return 0;
//}
// 上述代码中，num和*pFloat解读结果差别原因在于：
// 任意一个二进制浮点数都可以表示成
// V = (-1)^S*M*2^E
// (-1)^S表示符号位，当S=0，V为整数；当S=1，V为负数
// M表示有效数字，M是大于等于1，小于2的
// 2^E表示指数位
// 10：5.5
//  2：101.1
// 科学计数法：1.011 * 2 ^ 2
// 既然如此，那么规定只要存储S M E就可以了

// 对于32位浮点数float，最高1位存储S，接着8位存储指数E，剩下23存储有效数字M
// 对于64位浮点数double，最高1位存储S，接着11位存储指数E，剩下52位存储有效数字M
// 对于有效数字M，因为M可以写成1.xxxx形式，在计算机内部保存M时，默认这个数的第一位总是1
// 可以舍去，因此只保存后面的xxxx部分，这样可以多保存一位有效数字

// E是一个无符号整数，0 ~ 255，可是科学计数法的E是可以出现负数的
// 存入内存时E的真实值必须再加上一个中间数，对于8位的E，这个中间数是127
// 对于11位的E，这个中间数就是1023， 必须E如果是10，保存成32位浮点数时
// 必须保存成10+127=137，即100001001

//#include <stdio.h>
//
//int main()
//{
//	float f = 5.5f;
//	// 0 1000001 01100000000000000000000
//	// 0x40B000
//
//	return 0;
//}

// E为0，这时候浮点数的指数E等于1-127（或者1-1023）即为真实值
// 有效数字M不再加上第一位的1，而是为了0.xxxxx的小数，这样做是为了表示+-0，以及接近于0很小的数字

// E为1，如果有效数字M全为0，表示+-无穷大

// E不全为0或不全为1，这时，浮点数就采用下面的规则表示
// 即指数E的计算值减去127（或1023），得到真实值
// 再将有效数字M前加上第一位的1。

// 当整型n为9的时候
// 补码为00000000 00000000 00000000 00001001
// 0 00000000 00000000000000000001001
// S = 0
// E = -126
// M = 0.00000000000000000001001
// 浮点数在内存中可能无法精确保存
// double类型的精度必然比float更高
// 两个浮点数比较大小的时候，直接使用 == 比较可能存在问题，因此给一个精度即可
// if (abs(f-5.6)<=0.000001)


